<script setup lang="tsx">
import { computed, useAttrs } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { oneDarkTheme } from '@codemirror/theme-one-dark'
import { useDesign } from '@sat/shared-hooks'
import { useFormDisabled } from 'element-plus'
import type { EditorView, ViewUpdate } from '@codemirror/view'
import type { EditorState, Extension } from '@codemirror/state'
import { langMap } from './lang'

const props = defineProps<{
  lang: keyof typeof langMap
  dark?: boolean
  autofocus?: boolean
  disabled?: boolean
  indentWithTab?: boolean
  tabSize?: number
  placeholder?: string
  autoDestroy?: boolean
  extensions?: Extension[]
  onReady?: (payload: {
    view: EditorView
    state: EditorState
    container: HTMLDivElement
  }) => void
  onBlur?: (viewUpdate: ViewUpdate) => void
  onFocus?: (viewUpdate: ViewUpdate) => void
  onUpdate?: (viewUpdate: ViewUpdate) => void
  onChange?: (ditto: any) => void
  /* 其他参数可参照 vue-codemirror */
}>()

const inputDisabled = useFormDisabled()

const attrs = useAttrs()

const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('codemirror')
const extensions = computed(() => {
  const exts: any[] = [langMap[props.lang].lang()]

  if (langMap[props.lang].linter)
    exts.push(langMap[props.lang].linter?.())

  if (props.dark)
    exts.push(oneDarkTheme)

  if (props.extensions)
    exts.push(...props.extensions)

  return exts
})

const getProps = computed(() => {
  const propsObj = { ...props, ...attrs }
  const delKeys = ['extensions', 'lang', 'dark', 'disabled']
  for (const key in propsObj) {
    if (delKeys.includes(key)) {
      // @ts-ignore
      delete propsObj[key]
    }
  }
  return propsObj as Omit<
    typeof propsObj,
    'extensions' | 'lang' | 'dark' | 'disabled'
  >
})

const modelValue = defineModel<string>('modelValue', {
  default: '',
})
</script>

<template>
  <Codemirror
    v-model="modelValue"
    class="!block"
    :class="[prefixCls]"
    :extensions="extensions"
    v-bind="{
      ...getProps,
    }"
    :disabled="inputDisabled"
  />
</template>

<style lang="less" scoped></style>
